 /*******************************************************************************
  * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.actions;

 import java.lang.reflect.InvocationTargetException ;
 import java.net.URI ;

 import org.eclipse.core.commands.ExecutionException;
 import org.eclipse.core.filesystem.URIUtil;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
 import org.eclipse.core.resources.mapping.ResourceChangeValidator;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.MultiStatus;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.jface.dialogs.ErrorDialog;
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.operation.IRunnableWithProgress;
 import org.eclipse.jface.window.Window;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.dialogs.ProjectLocationSelectionDialog;
 import org.eclipse.ui.ide.IDE;
 import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
 import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;

 /**
  * Implementation class to perform the actual copying of project resources from
  * the clipboard when paste action is invoked.
  * <p>
  * This class may be instantiated; it is not intended to be subclassed.
  * </p>
  */
 public class CopyProjectOperation {

     /**
      * Status containing the errors detected when running the operation or
      * <code>null</code> if no errors detected.
      */
     private MultiStatus errorStatus;

     /**
      * The parent shell used to show any dialogs.
      */
     private Shell parentShell;

     private String [] modelProviderIds;

     /**
      * Validates that the copy of the project will not have undesirable side
      * effects.
      *
      * @param shell
      * a shell
      * @param project
      * the project being copied
      * @param newName
      * the new name of the project
      * @param modelProviderIds
      * the model provider ids of models that are known to the client
      * (and can hence be ignored)
      * @return whether the operation should proceed
      * @since 3.2
      * @deprecated As of 3.3, validation is performed in the undoable operation
      * executed by this operation.
      */
     protected static boolean validateCopy(Shell shell, IProject project,
             String newName, String [] modelProviderIds) {
         IResourceChangeDescriptionFactory factory = ResourceChangeValidator
                 .getValidator().createDeltaFactory();
         factory.copy(project, new Path(newName));
         return IDE.promptToConfirm(shell,
                 IDEWorkbenchMessages.CopyProjectAction_confirm, NLS.bind(
                         IDEWorkbenchMessages.CopyProjectAction_warning, project
                                 .getName()), factory.getDelta(),
                 modelProviderIds, false /* no need to sync exec */);
     }

     /**
      * Create a new operation initialized with a shell.
      *
      * @param shell
      * parent shell for error dialogs
      */
     public CopyProjectOperation(Shell shell) {
         parentShell = shell;
     }

     /**
      * Paste a copy of the project on the clipboard to the workspace.
      *
      * @param project
      * The project that is beign copied.
      */
     public void copyProject(IProject project) {
         errorStatus = null;

         // Get the project name and location in a two element list
 ProjectLocationSelectionDialog dialog = new ProjectLocationSelectionDialog(
                 parentShell, project);
         dialog.setTitle(IDEWorkbenchMessages.CopyProjectOperation_copyProject);
         if (dialog.open() != Window.OK) {
             return;
         }

         Object [] destinationPaths = dialog.getResult();
         if (destinationPaths == null) {
             return;
         }

         String newName = (String ) destinationPaths[0];
         URI newLocation = URIUtil.toURI((String )destinationPaths[1]);

         boolean completed = performProjectCopy(project, newName, newLocation);

         if (!completed) {
             return; // not appropriate to show errors
 }

         // If errors occurred, open an Error dialog
 if (errorStatus != null) {
             ErrorDialog.openError(parentShell,
                     IDEWorkbenchMessages.CopyProjectOperation_copyFailedTitle,
                     null, errorStatus);
             errorStatus = null;
         }
     }

     /**
      * Copies the project to the new values.
      *
      * @param project
      * the project to copy
      * @param projectName
      * the name of the copy
      * @param newLocation
      * IPath
      * @return <code>true</code> if the copy operation completed, and
      * <code>false</code> if it was abandoned part way
      */
     private boolean performProjectCopy(final IProject project,
             final String projectName, final URI newLocation) {
         IRunnableWithProgress op = new IRunnableWithProgress() {
             public void run(IProgressMonitor monitor) throws InvocationTargetException {
                 org.eclipse.ui.ide.undo.CopyProjectOperation op = new org.eclipse.ui.ide.undo.CopyProjectOperation(
                         project, projectName, newLocation,
                         IDEWorkbenchMessages.CopyProjectOperation_copyProject);
                 op.setModelProviderIds(getModelProviderIds());
                 try {
                     PlatformUI.getWorkbench().getOperationSupport()
                             .getOperationHistory().execute(
                                     op,
                                     monitor,
                                     WorkspaceUndoUtil
                                             .getUIInfoAdapter(parentShell));
                 } catch (final ExecutionException e) {
                     if (e.getCause() instanceof CoreException) {
                         recordError((CoreException)e.getCause());
                     } else {
                         throw new InvocationTargetException (e);
                     }
                 }
             }
         };

         try {
             new ProgressMonitorJobsDialog(parentShell).run(true, true, op);
         } catch (InterruptedException e) {
             return false;
         } catch (InvocationTargetException e) {
             final String message = e.getTargetException().getMessage();
             parentShell.getDisplay().syncExec(new Runnable () {
                 public void run() {
                     MessageDialog
                             .openError(
                                     parentShell,
                                     IDEWorkbenchMessages.CopyProjectOperation_copyFailedTitle,
                                     NLS
                                             .bind(
                                                     IDEWorkbenchMessages.CopyProjectOperation_internalError,
                                                     message));
                 }
             });
             return false;
         }

         return true;
     }

     /**
      * Records the core exception to be displayed to the user
      * once the action is finished.
      *
      * @param error a <code>CoreException</code>
      */
     private void recordError(CoreException error) {

         if (errorStatus == null) {
             errorStatus = new MultiStatus(
                     PlatformUI.PLUGIN_ID,
                     IStatus.ERROR,
                     IDEWorkbenchMessages.CopyProjectOperation_copyFailedMessage,
                     error);
         }

         errorStatus.merge(error.getStatus());
     }

     /**
      * Returns the model provider ids that are known to the client
      * that instantiated this operation.
      *
      * @return the model provider ids that are known to the client
      * that instantiated this operation.
      * @since 3.2
      */
     public String [] getModelProviderIds() {
         return modelProviderIds;
     }

     /**
      * Sets the model provider ids that are known to the client that
      * instantiated this operation. Any potential side effects reported by these
      * models during validation will be ignored.
      *
      * @param modelProviderIds
      * the model providers known to the client who is using this
      * operation.
      * @since 3.2
      */
     public void setModelProviderIds(String [] modelProviderIds) {
         this.modelProviderIds = modelProviderIds;
     }
 }

